import os
from typing import List
import pickle
import Logger

from PySide2.QtWidgets import *
from PySide2.QtCore import QFile, QStringListModel, Qt, QRect

import Util
from ExcelData import EData, ExcelData, TableData, SaveType, SyncJsonDir, SyncPublishServer
from UiSetting import Ui_SettingDialog

COL_CPDIR: [] = ["启用", "复制目录"]
COL_CPDIR_WDTH: [] = [80, 120]
COL_CPDIR_ENABLED: int = 0
COL_CPDIR_PATH: int = 1

COL_PBSERVER: [] = ["服务器名", "服务器地址", "识别标识(不能重复)"] #, "开启", "用户", "密码"
COL_PBSERVER_WDTH: [] = [150, 400, 80] #, 70, 80, 100
# COL_PBSERVER_ENABLED: int = 0
COL_PBSERVER_CAPTION: int = 0
COL_PBSERVER_PATH: int = 1
COL_PBSERVER_TAG: int = 2
# COL_PBSERVER_USER: int = 4
# COL_PBSERVER_PWD: int = 5

class SettingDialog(QDialog, Ui_SettingDialog):
    edata: EData
    logger: Logger
    refreshingServerList: bool

    def __init__(self):
        super(SettingDialog, self).__init__()
        self.logger = Logger.Logger()
        self.edata = EData()

        self.ui = Ui_SettingDialog()
        self.ui.setupUi(self)

        # 绑定按钮
        self.ui.btnDefault.clicked.connect(self.onBthDefaultClick)
        self.ui.btnOk.clicked.connect(self.onBthOkClick)
        self.ui.btnClose.clicked.connect(self.onBthCloseClick)

        self.ui.btnAddCopyDir.clicked.connect(self.onBtnAddCopyDirClick)
        self.ui.btnDelCopyDir.clicked.connect(self.onBtnDelCopyDirClick)
        self.ui.btnAddServer.clicked.connect(self.onBtnAddServerClick)
        self.ui.btnDelServer.clicked.connect(self.onBtnDelServerClick)

        self.ui.btnSelectDirJavaFileCopy.clicked.connect(self.onSelectDirJavaFileCopyClick)
        self.ui.btnSelectDirLayaFileCopy.clicked.connect(self.onSelectDirLayaFileCopyClick)
        self.ui.btnClearCopyDir.clicked.connect(self.onBtnClearCopyDirClick)
        self.ui.btnClearServer.clicked.connect(self.onBtnClearServerClick)

        self.ui.btnCheckSvnAddr.clicked.connect(self.onBtnCheckSvnAddrClick)

        self.ui.listCopyDir.itemClicked.connect(self.onListCopyDirClick)

        self.ui.btnImport.clicked.connect(self.ontnImport)
        self.ui.btnExport.clicked.connect(self.onBtnExport)

        self.ui.btnMoveUp1.clicked.connect(self.onMoveUp1Click)
        self.ui.btnMoveDown1.clicked.connect(self.onMoveDown1Click)
        self.ui.btnMoveUp2.clicked.connect(self.onMoveUp2Click)
        self.ui.btnMoveDown2.clicked.connect(self.onMoveDown2Click)

        # 设置表头样式
        Util.initColumnListFile(self.ui.listCopyDir, COL_CPDIR, COL_CPDIR_WDTH, Util.HEADER_STYLE_GRAY)

        self.refreshingServerList = False
        self.ui.listServer.itemClicked.connect(self.onListServerClick)
        self.ui.listServer.itemChanged.connect(self.onListServerChange)
        self.ui.listServer.itemDoubleClicked.connect(self.onListServerDoubleClicked)
        # 设置表头样式
        Util.initColumnListFile(self.ui.listServer, COL_PBSERVER, COL_PBSERVER_WDTH, Util.HEADER_STYLE_GRAY)


    def show(self):
        print("打开配置UI")
        self.loadFromData()
        super(SettingDialog, self).show()
        # 刷新列表
        self.refreshListCopyDir()
        self.refreshListServer()
        self.resetFormPosition()

    isFirstShow: bool = True

    def resetFormPosition(self):
        # 调整窗口位置，不阻挡logs
        # Util.setToTop(self)
        mainRect: QRect = Util.mainForm.geometry()
        if self.isFirstShow:
            # pyside2奇怪的bug，第一次打开坐标不准，第二次才准，所以只能用标记处理第一次打开的坐标
            self.isFirstShow = False
            x = Util.mainForm.x() + ((Util.mainForm.width() - self.width()) / 2)
            y = Util.mainForm.y()
        else:
            mainRect: QRect = Util.mainForm.geometry()
            x = mainRect.x() + ((mainRect.width() - self.width()) / 2)
            y = mainRect.y()

        self.move(x, y)

    def loadFromData(self):

        self.ui.txtCfgSheetName.setText(self.edata.setting.readerCfgSheetName)
        self.ui.txtTagImportSheets.setText(self.edata.setting.readerCfgTagImportSheets)
        self.ui.txtCfgIgnoreColumn.setText(self.edata.setting.readerCfgIgnoreColumn)

        self.ui.txtDirExcelFile.setText(self.edata.setting.defDirExcelFile)
        self.ui.txtDirJsonFile.setText(self.edata.setting.defDirJsonFile)
        self.ui.txtDefineJsonFile.setText(self.edata.setting.defDefineJsonFile)
        self.ui.txtDirJavaFile.setText(self.edata.setting.genDirJavaFile)
        self.ui.txtDirLayaFile.setText(self.edata.setting.genDirLayaFile)
        self.ui.txtZipFile.setText(self.edata.setting.genZipFile)

        self.ui.txtLibConstantClass.setText(self.edata.setting.genLibConstantClass)
        self.ui.txtLibEasyAccessClass.setText(self.edata.setting.genLibEasyAccessClass)
        self.ui.txtLibPrefix.setText(self.edata.setting.genLibPrefix)

        self.ui.txtSvnUrl.setText(self.edata.setting.svnUrl)
        self.ui.txtSvnUser.setText(self.edata.setting.svnUser)
        self.ui.txtSvnPwd.setText(self.edata.setting.svnPwd)

        self.ui.txtDirJavaFileCopy.setText(self.edata.setting.genDirJavaFileCopy)
        self.ui.txtDirLayaFileCopy.setText(self.edata.setting.genDirLayaFileCopy)

        # self.ui.txtCfgServerUrl.setText(self.edata.setting.cfgServerUrl)
        # self.ui.txtCfgServerUser.setText(self.edata.setting.cfgServerUser)
        # self.ui.txtCfgServerPwd.setText(self.edata.setting.cfgServerPwd)

        self.ui.chkAutoOpenFolderGenJson.setChecked(self.edata.setting.chkAutoOpenFolderGenJson)
        self.ui.chkAutoOpenFolderCopy.setChecked(self.edata.setting.chkAutoOpenFolderCopy)

    def saveFromData(self):
        self.edata.setting.readerCfgSheetName = self.ui.txtCfgSheetName.text()
        self.edata.setting.readerCfgTagImportSheets = self.ui.txtTagImportSheets.text()
        self.edata.setting.readerCfgIgnoreColumn = self.ui.txtCfgIgnoreColumn.text()

        self.edata.setting.defDirExcelFile = self.ui.txtDirExcelFile.text()
        self.edata.setting.defDirJsonFile = self.ui.txtDirJsonFile.text()
        self.edata.setting.defDefineJsonFile = self.ui.txtDefineJsonFile.text()
        self.edata.setting.genDirJavaFile = self.ui.txtDirJavaFile.text()
        self.edata.setting.genDirLayaFile = self.ui.txtDirLayaFile.text()
        self.edata.setting.genZipFile = self.ui.txtZipFile.text()

        self.edata.setting.genLibConstantClass = self.ui.txtLibConstantClass.text()
        self.edata.setting.genLibEasyAccessClass = self.ui.txtLibEasyAccessClass.text()
        self.edata.setting.genLibPrefix = self.ui.txtLibPrefix.text()

        self.edata.setting.svnUrl = self.ui.txtSvnUrl.text().strip(" ")
        self.edata.setting.svnUser = self.ui.txtSvnUser.text().strip(" ")
        self.edata.setting.svnPwd = self.ui.txtSvnPwd.text().strip(" ")

        # self.edata.setting.cfgServerUrl = self.ui.txtCfgServerUrl.text().strip(" ")
        # self.edata.setting.cfgServerUser = self.ui.txtCfgServerUser.text().strip(" ")
        # self.edata.setting.cfgServerPwd = self.ui.txtCfgServerPwd.text().strip(" ")

        self.edata.setting.genDirJavaFileCopy = self.ui.txtDirJavaFileCopy.text()
        self.edata.setting.genDirLayaFileCopy = self.ui.txtDirLayaFileCopy.text()

    def onBthDefaultClick(self):
        self.edata.setting.resetDefault(True)
        self.loadFromData()

    def onBthOkClick(self):
        print("保存设置")
        self.saveFromData()
        self.edata.save(SaveType.Setting)
        self.close()

    def onBthCloseClick(self):
        self.close()


    ####################################################################
    #   【列表排序】相关
    ####################################################################
    def onMoveUp1Click(self):
        """文件排序上移"""
        swapA = self.ui.listCopyDir.currentRow()
        if self.ui.listCopyDir.currentRow() < 0:
            QMessageBox.warning(self, "提示", "你还没有选择要调整顺序的发布目录!")
            return
        swapB = swapA - 1
        if swapB < 0:
            return

        self.edata.setting.swapSyncDirsItems(swapA, swapB)
        selectItem: QTableWidgetItem = self.ui.listCopyDir.item(swapB, 1)
        self.ui.listCopyDir.setCurrentItem(selectItem)
        # 刷新列表
        self.refreshListCopyDir()

    def onMoveDown1Click(self):
        """文件排序下移"""
        swapA = self.ui.listCopyDir.currentRow()
        if self.ui.listCopyDir.currentRow() < 0:
            QMessageBox.warning(self, "提示", "你还没有选择要调整顺序的发布目录!")
            return
        swapB = swapA + 1
        if swapB > len(self.edata.setting.syncDirs) - 1:
            return
        self.edata.setting.swapSyncDirsItems(swapA, swapB)
        selectItem: QTableWidgetItem = self.ui.listCopyDir.item(swapB, 1)
        self.ui.listCopyDir.setCurrentItem(selectItem)
        # 刷新列表
        self.refreshListCopyDir()

    def onMoveUp2Click(self):
        """文件排序上移"""
        swapA = self.ui.listServer.currentRow()
        if self.ui.listServer.currentRow() < 0:
            QMessageBox.warning(self, "提示", "你还没有选择要调整顺序的服务器！")
            return
        swapB = swapA - 1
        if swapB < 0:
            return

        self.edata.setting.swapSyncServersItems(swapA, swapB)
        selectItem: QTableWidgetItem = self.ui.listServer.item(swapB, 1)
        self.ui.listServer.setCurrentItem(selectItem)
        # 刷新列表
        self.refreshListServer()

    def onMoveDown2Click(self):
        swapA = self.ui.listServer.currentRow()
        if self.ui.listServer.currentRow() < 0:
            QMessageBox.warning(self, "提示", "你还没有选择要调整顺序的服务器!")
            return
        swapB = swapA + 1
        if swapB > len(self.edata.setting.syncServers) - 1:
            return
        self.edata.setting.swapSyncServersItems(swapA, swapB)
        selectItem: QTableWidgetItem = self.ui.listServer.item(swapB, 1)
        self.ui.listServer.setCurrentItem(selectItem)
        # 刷新列表
        self.refreshListServer()

    ####################################################################
    #   【发布设置】相关
    ####################################################################

    def onSelectDirJavaFileCopyClick(self):
        path = QFileDialog.getExistingDirectory(self, "选择JavaVo生成后自动拷贝目录", "")
        if not path is None:
            path = path.replace("/", "\\").replace(self.edata.currentPath, "")
            if not path.endswith("\\"):
                path += "\\"
            self.ui.txtDirJavaFileCopy.setText(path)

    def onSelectDirLayaFileCopyClick(self):
        path = QFileDialog.getExistingDirectory(self, "选择LayaVo生成后自动拷贝目录", "")
        if not path is None:
            path = path.replace("/", "\\").replace(self.edata.currentPath, "")
            if not path.endswith("\\"):
                path += "\\"
            self.ui.txtDirLayaFileCopy.setText(path)

    ####################################################################
    #   【发布列表】相关
    ####################################################################

    def refreshListCopyDir(self):
        """刷新左边【发布目录】表格数据"""
        self.ui.listCopyDir.setRowCount(len(self.edata.setting.syncDirs))
        count: int = 0
        for (fKey, fData1) in self.edata.setting.syncDirs.items():
            fData: SyncJsonDir = fData1

            # 插入单选框-启用
            itemEnabled = QTableWidgetItem("启用")
            if fData.isEnabledChecked:
                itemEnabled.setCheckState(Qt.Checked)
            else:
                itemEnabled.setCheckState(Qt.Unchecked)
            itemEnabled.setTextAlignment(Qt.AlignCenter)
            # 目录地址
            itemDir: QTableWidgetItem = QTableWidgetItem(fData.dirPath)

            self.ui.listCopyDir.setItem(count, COL_CPDIR_ENABLED, itemEnabled)
            self.ui.listCopyDir.setItem(count, COL_CPDIR_PATH, itemDir)
            count += 1

    def onBtnDelCopyDirClick(self):
        """按钮: [同步数据]删除选中"""
        print(self.ui.listCopyDir.currentRow())
        if self.ui.listCopyDir.currentRow() < 0:
            QMessageBox.warning(self, "提示", "你还没有选择要删除的目录地址！")
            return
        dirItem: QTableWidgetItem = self.ui.listCopyDir.item(self.ui.listCopyDir.currentRow(), COL_CPDIR_PATH)
        syncJsonDir: SyncJsonDir = self.edata.setting.syncDirs.get(dirItem.text())
        if not syncJsonDir is None:
            del self.edata.setting.syncDirs[dirItem.text()]
        self.refreshListCopyDir()

    def onListCopyDirClick(self, item: QTableWidgetItem):
        """点击左边【发布目录】表格数据"""
        print("【发布目录】QTable 您点击了：" + item.text() + " row:" + str(item.row()))
        self.syncCheckStateCopyDir()  # 同步勾选状态

    def syncCheckStateCopyDir(self):
        """同步左边【发布目录】表格勾选状态到记录库"""
        for i in range(0, self.ui.listCopyDir.rowCount()):
            checkboxEnabled: QTableWidgetItem = self.ui.listCopyDir.item(i, COL_CPDIR_ENABLED)
            dirItem: QTableWidgetItem = self.ui.listCopyDir.item(i, COL_CPDIR_PATH)
            data: SyncJsonDir = self.edata.setting.syncDirs[dirItem.text()]
            if data is None:
                QMessageBox.information(self, "警告", "勾选出错! 没对应路径")
                continue

            if checkboxEnabled.checkState() == Qt.Checked:
                data.isEnabledChecked = True
            else:
                data.isEnabledChecked = False



    def onBtnAddCopyDirClick(self):
        """按钮: [同步数据]添加目录"""
        path = QFileDialog.getExistingDirectory(self, "选择自动复制数据目标目录", "")
        if (not path is None) and ("" != path):
            path = path.replace("/", "\\").replace(self.edata.currentPath, "")
            if not path.endswith("\\"):
                path += "\\"
            # 添加到列表
            folder: SyncJsonDir = self.edata.setting.syncDirs.get(path)
            if folder is None:
                newFolder: SyncJsonDir = SyncJsonDir()
                newFolder.isOpenFolderChecked = False
                newFolder.isEnabledChecked = False
                newFolder.isListChecked = True
                newFolder.dirPath = path
                self.edata.setting.syncDirs[path] = newFolder
            else:
                QMessageBox.warning(self, "提示", "该目录已经存在列表中！")
            # 刷新列表
            self.refreshListCopyDir()

    def onBtnClearCopyDirClick(self):
        self.edata.setting.syncDirs.clear()
        self.refreshListCopyDir()

    ####################################################################
    #   【配置服务器】相关
    ####################################################################

    def refreshListServer(self):
        """下方【发布服务器】表格数据"""
        self.refreshingServerList = True
        self.ui.listServer.setRowCount(len(self.edata.setting.syncServers))
        count: int = 0
        for (fKey, fData1) in self.edata.setting.syncServers.items():
            fData: SyncPublishServer = fData1
            # 插入单选框-启用
            # itemEnabled = QTableWidgetItem("启用")
            # if fData.isEnabledChecked:
            #     itemEnabled.setCheckState(Qt.Checked)
            # else:
            #     itemEnabled.setCheckState(Qt.Unchecked)
            # itemEnabled.setTextAlignment(Qt.AlignCenter)

            # 服务器名
            itemCaption: QTableWidgetItem = QTableWidgetItem(fData.caption)
            # 服务器地址
            itemPath: QTableWidgetItem = QTableWidgetItem(fData.serverPath)
            # 服务器名
            itemTag: QTableWidgetItem = QTableWidgetItem(fData.tag)
            # 服务器地址
            # itemUser: QTableWidgetItem = QTableWidgetItem(fData.user)
            # 服务器地址
            # itemPwd: QTableWidgetItem = QTableWidgetItem(fData.pwd)

            # self.ui.listServer.setItem(count, COL_PBSERVER_ENABLED, itemEnabled)
            self.ui.listServer.setItem(count, COL_PBSERVER_CAPTION, itemCaption)
            self.ui.listServer.setItem(count, COL_PBSERVER_PATH, itemPath)
            self.ui.listServer.setItem(count, COL_PBSERVER_TAG, itemTag)
            # self.ui.listServer.setItem(count, COL_PBSERVER_USER, itemUser)
            # self.ui.listServer.setItem(count, COL_PBSERVER_PWD, itemPwd)
            count += 1
        self.refreshingServerList = False

    def onBtnDelServerClick(self):
        """按钮: [发布服务器]删除选中"""
        print(self.ui.listServer.currentRow())
        if self.ui.listServer.currentRow() < 0:
            QMessageBox.warning(self, "提示", "你还没有选择要删除的同步服务器配置！")
            return
        keyItem: QTableWidgetItem = self.ui.listServer.item(self.ui.listServer.currentRow(), COL_PBSERVER_CAPTION)
        syncPbServer: SyncPublishServer = self.edata.setting.syncServers.get(keyItem.text())
        if not syncPbServer is None:
            del self.edata.setting.syncServers[keyItem.text()]
        self.refreshListServer()

    def onListServerClick(self, item: QTableWidgetItem):
        """点击下方【发布服务器】表格数据"""
        print("【发布服务器】QTable 您点击了：" + item.text() + " row:" + str(item.row()) + " col:" + str(item.column()))
        # if item.column()==0:
        #     self.syncCheckStateServer()  # 同步勾选状态

    # def syncCheckStateServer(self):
    #     """同步下方【发布服务器】表格勾选状态到记录库"""
    #     for i in range(0, self.ui.listServer.rowCount()):
    #         checkboxEnabled: QTableWidgetItem = self.ui.listServer.item(i, COL_PBSERVER_ENABLED)
    #         keyItem: QTableWidgetItem = self.ui.listServer.item(i, COL_PBSERVER_CAPTION)
    #         data: SyncPublishServer = self.edata.setting.syncServers[keyItem.text()]
    #         if data is None:
    #             QMessageBox.information(self, "警告", "勾选出错! 没对应服务器")
    #             continue
    #
    #         if checkboxEnabled.checkState() == Qt.Checked:
    #             data.isEnabledChecked = True
    #         else:
    #             data.isEnabledChecked = False


    def getServerDictItemByKey(self, searchKey):
        """根据键值找到对应的服务器信息"""
        for key, value in self.edata.setting.syncServers.items():
            if(key==searchKey):
                return value;

    selectedOldServerKey: str = ""

    def onListServerDoubleClicked(self, item: QTableWidgetItem):
        """点击下方【发布服务器】表格数据"""
        print("【发布服务器】QTable 您双击了：" + item.text() + " row:" + str(item.row()))
        self.selectedOldServerKey = item.text();


    def onBtnAddServerClick(self):
        """按钮: [发布服务器]添加目录"""

        enter, ok = QInputDialog.getText(self, "起名", "请为配置改名，服务器端识别用", QLineEdit.EchoMode.Normal, "新建名字")
        print(enter)
        print(ok)
        if(ok==True):
            if(enter=="新建名字"):
                QMessageBox.warning(self, "提示", "请修改名字！")
                return
            if(self.getServerDictItemByKey(enter)!=None):
                QMessageBox.warning(self, "提示", "名字重复率！")
                return

            newFolder: SyncPublishServer = SyncPublishServer()
            newFolder.isEnabledChecked = False
            newFolder.caption = enter
            newFolder.serverPath = "http://127.0.0.1:8080/"
            self.edata.setting.syncServers[newFolder.caption] = newFolder
            # 刷新列表
            self.refreshListServer()
            print("添加一个新发布服务器：" + newFolder.caption);


    def onListServerChange(self, item: QTableWidgetItem):
        print("【发布服务器】QTable 更新了：" + item.text() + " row:" + str(item.row()) + " col:" + str(item.column()))
        row = item.row()
        col = item.column()
        # if col < 1:
        #     QMessageBox.warning(self, "提示", "名字不能修改")
        #     self.refreshListServer()
        #     return

        if(self.refreshingServerList == True):
            return
        if row > self.ui.listServer.rowCount() - 1:
            QMessageBox.warning(self, "提示", "选择的数据包不在范围内！")
            return
        #提取key (key不能重复)
        keyItem: QTableWidgetItem = self.ui.listServer.item(row, COL_PBSERVER_CAPTION)
        key = keyItem.text()
        #提取tag (tag不能重复)
        tagItem: QTableWidgetItem = self.ui.listServer.item(row, COL_PBSERVER_TAG)
        tag = tagItem.text()

        for k, v in self.edata.setting.syncServers.items():
            server: SyncPublishServer = v
            if col==COL_PBSERVER_TAG and server.tag == tag:
                # item.setText(server.tag)
                QMessageBox.warning(self, "提示", "Tag标识重复了!")
                self.refreshListServer()
                return
            if col==COL_PBSERVER_CAPTION and server.caption == key:
                # item.setText(server.caption)
                QMessageBox.warning(self, "提示", "名字重复了!")
                self.refreshListServer()
                return

        if col==COL_PBSERVER_CAPTION:
            key = self.selectedOldServerKey
        edataItem = self.getServerDictItemByKey(key)
        print("【发布服务器】QTable 原数据：" + edataItem.caption + ", " + edataItem.serverPath + ", " + edataItem.tag)  # + ", " + edataItem.user + ", " + edataItem.pwd
        if col==COL_PBSERVER_CAPTION:
            oldKey = edataItem.caption
            edataItem.caption = keyItem.text()
            del self.edata.setting.syncServers[oldKey]
            self.edata.setting.syncServers[edataItem.caption] = edataItem
            self.refreshListServer()
        else:
            item: QTableWidgetItem = self.ui.listServer.item(row, col)
            if col == COL_PBSERVER_TAG:
                edataItem.tag = item.text()
            if col == COL_PBSERVER_PATH:
                edataItem.serverPath = item.text()
            # if col == COL_PBSERVER_USER:
            #     edataItem.user = item.text()
            # if col == COL_PBSERVER_PWD:
            #     edataItem.pwd = item.text()

        print("【发布服务器】QTable 修改后：" + str(edataItem.isEnabledChecked) + ", " + edataItem.caption + ", " + edataItem.serverPath) #  + ", " + edataItem.user + ", " + edataItem.pwd
        self.refreshListServer()


    def onBtnClearServerClick(self):
        self.edata.setting.syncServers.clear()
        self.refreshListServer()

    def onBtnCheckSvnAddrClick(self):
        QMessageBox.warning(self, "提示", "功能即将推出！")
        pass

    def ontnImport(self):
        filePath = QFileDialog.getOpenFileName(self, "选择导入服务器列表文件", "./", "Serverlist Files (*.esl)")
        if not os.path.isfile(filePath[0]):
            return
        print('File:', filePath)
        fileName = os.path.basename(filePath[0])
        self.logger.logNotice('导入服务器列表文件:' + fileName, self)

        if not os.path.isfile(fileName):
            return False
        f = open(fileName, "rb")
        self.edata.setting.syncServers = pickle.load(f)
        f.close()
        self.refreshListServer()

    def onBtnExport(self):
        filePath = QFileDialog.getSaveFileName(self, "输入要导出的服务器列表文件", "./", "Serverlist Files (*.esl)")
        savepath = "serverlist1"
        if filePath[0] != "":  # 没有选择文件，退出
            savepath = filePath[0]
        # if not os.path.isfile(filePath[0]):
        #     return
        print('File:', savepath)
        fileName = os.path.basename(savepath)
        self.logger.logNotice('保存服务器列表文件:' + fileName, self)

        f = open(fileName, "wb")
        pickle.dump(self.edata.setting.syncServers, f)
        f.close()